﻿namespace PhotobucketNet
{
    using System;
    using System.Security.Cryptography;
    using System.Text;

    internal class OAuth
    {
        private string _apiKey;
        private string _apiSecret;
        private string _baseUrl;
        private Random _random = new Random();
        private const string _uploadfile = "uploadfile";
        private const string HMACSHA1SignatureType = "HMAC-SHA1";
        private const string HomeUrl = "homeurl";
        private const string NextStep = "next_step";
        private const string OAuthCallbackKey = "oauth_callback";
        private const string OAuthConsumerKeyKey = "oauth_consumer_key";
        private const string OAuthNonceKey = "oauth_nonce";
        private const string OAuthParameterPrefix = "oauth_";
        private const string OAuthSignatureKey = "oauth_signature";
        private const string OAuthSignatureMethodKey = "oauth_signature_method";
        private const string OAuthTimestampKey = "oauth_timestamp";
        private const string OAuthTokenKey = "oauth_token";
        private const string OAuthTokenSecretKey = "oauth_token_secret";
        private const string OAuthVersion = "1.0";
        private const string OAuthVersionKey = "oauth_version";
        private const string Subdomain = "subdomain";
        private const string unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
        private const string Username = "username";

        public OAuth(string baseUrl, string apiKey, string apiSecret)
        {
            this._baseUrl = baseUrl;
            this._apiKey = apiKey;
            this._apiSecret = apiSecret;
        }

        public string GenerateHashedSignature(string relativeUrl, string httpMethod, string tokenSecret, string timestamp, string nonce, QueryParameterList paramaters)
        {
            return this.GenerateHashedSignature(relativeUrl, httpMethod, this._apiSecret, tokenSecret, timestamp, nonce, paramaters);
        }

        public string GenerateHashedSignature(string relativeUrl, string httpMethod, string apiSecret, string tokenSecret, string timestamp, string nonce, QueryParameterList paramaters)
        {
            string s = this.GenerateSignatureBase(this._baseUrl + relativeUrl, httpMethod, timestamp, nonce, paramaters);
            HMACSHA1 hmacsha = new HMACSHA1();
            hmacsha.Key = Encoding.ASCII.GetBytes(string.Format("{0}&{1}", this.UrlEncode(apiSecret), this.UrlEncode(tokenSecret)));
            byte[] bytes = Encoding.ASCII.GetBytes(s);
            return Convert.ToBase64String(hmacsha.ComputeHash(bytes));
        }

        private string GenerateNonce()
        {
            return this._random.Next(0xbc614e, 0x3b9ac9ff).ToString();
        }

        public QueryParameterList GenerateOAuthParamaters(string relativeUrl, string httpMethod, PhotobucketToken token, QueryParameterList paramaters)
        {
            string str = this.GenerateNonce();
            string str2 = this.GenerateTimeStamp();
            if (paramaters == null)
            {
                paramaters = new QueryParameterList();
            }
            paramaters.Add(new QueryParameter("oauth_version", "1.0"));
            paramaters.Add(new QueryParameter("oauth_nonce", str));
            paramaters.Add(new QueryParameter("oauth_timestamp", str2));
            paramaters.Add(new QueryParameter("oauth_signature_method", "HMAC-SHA1"));
            paramaters.Add(new QueryParameter("oauth_consumer_key", this._apiKey));
            if (!string.IsNullOrEmpty(token.Token))
            {
                paramaters.Add(new QueryParameter("oauth_token", token.Token));
            }
            string url = this.GenerateHashedSignature(relativeUrl, httpMethod, token.TokenSecret, str2, str, paramaters);
            paramaters.Add(new QueryParameter("oauth_signature", this.UrlEncode(url)));
            paramaters.Sort();
            return paramaters;
        }

        private string GenerateSignatureBase(string url, string httpMethod, string timestamp, string nonce, QueryParameterList paramaters)
        {
            if (string.IsNullOrEmpty(httpMethod))
            {
                throw new ArgumentNullException("httpMethod empty");
            }
            paramaters.Sort();
            string str = paramaters.NormalizeRequestParameters();
            StringBuilder builder = new StringBuilder();
            builder.AppendFormat("{0}&", httpMethod.ToUpper());
            builder.AppendFormat("{0}&", this.UrlEncode(url));
            builder.AppendFormat("{0}", this.UrlEncode(str));
            return builder.ToString();
        }

        private string GenerateTimeStamp()
        {
            TimeSpan span = (TimeSpan) (DateTime.UtcNow - new DateTime(0x7b2, 1, 1, 0, 0, 0, 0));
            return Convert.ToInt32(span.TotalSeconds).ToString();
        }

        public string GenerateURL(string authedBaseUrl, string relativeUrl, string httpMethod, PhotobucketToken token)
        {
            return this.GenerateURL(authedBaseUrl, relativeUrl, httpMethod, token, null);
        }

        public string GenerateURL(string authedBaseUrl, string relativeUrl, string httpMethod, PhotobucketToken token, QueryParameterList paramaters)
        {
            if (string.IsNullOrEmpty(authedBaseUrl))
            {
                authedBaseUrl = this._baseUrl;
            }
            if (string.IsNullOrEmpty(httpMethod))
            {
                throw new ArgumentNullException("httpMethod empty");
            }
            string str = this.GenerateOAuthParamaters(relativeUrl, httpMethod, token, paramaters).NormalizeRequestParameters();
            return (authedBaseUrl + relativeUrl + "?" + str);
        }

        public ConsumerToken GetConsumerTokenFromResponse(string response)
        {
            QueryParameterList queryParameters = QueryUtility.GetQueryParameters(response, string.Empty);
            ConsumerToken token = new ConsumerToken();
            foreach (QueryParameter parameter in queryParameters)
            {
                if (parameter.Name == "oauth_token")
                {
                    token.Token = this.UrlDecode(parameter.Value);
                }
                else
                {
                    if (parameter.Name == "oauth_token_secret")
                    {
                        token.TokenSecret = this.UrlDecode(parameter.Value);
                        continue;
                    }
                    if (parameter.Name == "next_step")
                    {
                        token.NextStepUrl = this.UrlDecode(parameter.Value);
                    }
                }
            }
            return token;
        }

        public UserToken GetUserTokenFromResponse(string response)
        {
            QueryParameterList queryParameters = QueryUtility.GetQueryParameters(response, string.Empty);
            UserToken token = new UserToken();
            foreach (QueryParameter parameter in queryParameters)
            {
                if (parameter.Name == "oauth_token")
                {
                    token.Token = this.UrlDecode(parameter.Value);
                }
                else
                {
                    if (parameter.Name == "oauth_token_secret")
                    {
                        token.TokenSecret = this.UrlDecode(parameter.Value);
                        continue;
                    }
                    if (parameter.Name == "username")
                    {
                        token.Username = this.UrlDecode(parameter.Value);
                        continue;
                    }
                    if (parameter.Name == "subdomain")
                    {
                        token.Subdomain = this.UrlDecode(parameter.Value);
                        continue;
                    }
                    if (parameter.Name == "homeurl")
                    {
                        token.UserHomeUrl = this.UrlDecode(parameter.Value);
                    }
                }
            }
            return token;
        }

        public string UrlDecode(string Url)
        {
            StringBuilder builder = new StringBuilder();
            string str = "";
            bool flag = false;
            foreach (char ch in Url)
            {
                if (flag)
                {
                    if (str.Length == 0)
                    {
                        str = str + ch;
                    }
                    else if (str.Length == 1)
                    {
                        str = str + ch;
                        flag = false;
                        string str2 = char.ConvertFromUtf32(Convert.ToInt32(str, 0x10));
                        builder.Append(str2);
                        str = "";
                    }
                }
                else if (ch == '%')
                {
                    flag = true;
                }
                else
                {
                    builder.Append(ch);
                }
            }
            return builder.ToString();
        }

        public string UrlEncode(string Url)
        {
            if (string.IsNullOrEmpty(Url))
            {
                return "";
            }
            StringBuilder builder = new StringBuilder();
            foreach (char ch in Url)
            {
                if ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~".IndexOf(ch) != -1)
                {
                    builder.Append(ch);
                }
                else
                {
                    builder.Append('%' + string.Format("{0:X2}", (int) ch));
                }
            }
            return builder.ToString();
        }
    }
}

